from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from bs4 import BeautifulSoup
import time
from bs4 import BeautifulSoup
import re
import platform
from enum import Enum, auto
from selenium_utils import get_real_page, DouyinDownloader
from speech_to_text import SpeechToTextProcessor
import os
import requests
import sys
import os
import shutil
from dataclasses import dataclass
from typing import Optional, Dict, Any
import json


def compress_video_async(video_path: str):
    """异步压缩视频文件
    
    参数:
        video_path: 要压缩的视频文件路径
        
    功能:
        1. 使用gzip进行压缩
        2. 在后台线程中运行，不阻塞主流程
        3. 自动处理异常并记录日志
    """
    import gzip
    import threading
    import shutil
    
    def _compress():
        """实际执行压缩的内部函数"""
        try:
            compressed_path = f"{video_path}.gz"
            print(f"开始压缩视频: {video_path} -> {compressed_path}")
            
            with open(video_path, 'rb') as f_in:
                with gzip.open(compressed_path, 'wb') as f_out:
                    shutil.copyfileobj(f_in, f_out)
                    
            print(f"视频压缩完成: {compressed_path}")
        except Exception as e:
            print(f"视频压缩失败: {str(e)}")
    
    # 创建并启动后台线程
    threading.Thread(target=_compress, daemon=True).start()
    
def extract_video_url(html):
    """从HTML中提取视频URL
    
    参数:
        html: 网页HTML内容
        
    返回:
        str: 视频URL
        
    异常:
        ValueError: 当未找到视频URL时抛出
    """
    soup = BeautifulSoup(html, 'html.parser')
    source_tags = soup.find_all('source', src=True)
    
    if not source_tags:
        raise ValueError("HTML中未找到<source>标签")
        
    video_urls = [tag['src'] for tag in source_tags]
    
    if not video_urls:
        raise ValueError("<source>标签中没有有效的视频URL")
        
    return video_urls[0]
    
def extract_url(input_text):
    """从输入文本中提取URL"""
    url_pattern = r'(http[s]?:\/\/[^\s,，]+)'
    match = re.search(url_pattern, input_text)
    if match:
        return match.group(0)
    return None


def extract_douyin_shortlink_id(url: str) -> str:
    """
    从抖音分享链接中提取短链接标识（如XM9ZkmRhr10）
    
    参数：
    url (str)：抖音分享链接，支持以下格式：
               - https://v.douyin.com/XM9ZkmRhr10/
               - http://v.douyin.com/XM9ZkmRhr10
               - https://m.douyin.com/XM9ZkmRhr10/
               - https://douyin.com/XM9ZkmRhr10
    
    返回：
    str：提取到的短链接标识（如XM9ZkmRhr10），若未匹配则返回空字符串
    """
    # 正则匹配逻辑：
    # 1. 匹配域名部分（支持v.douyin.com/m.douyin.com/douyin.com）
    # 2. 匹配短链接标识（由字母和数字组成的8-12位字符）
    pattern = r'https?://(?:v|m)?\.douyin\.com/([A-Za-z_0-9-]{3,120})/?'
    match = re.search(pattern, url)
    return match.group(1) if match else ''


def move_file(source, destination):
    """移动文件到指定目录
    增强路径处理，确保目标路径格式正确
    
    参数:
        source: 源文件路径
        destination: 目标路径（支持相对路径）
    """
    try:
        print(f"尝试移动文件: {source} 到 {destination}")
        if not os.path.exists(source):
            raise FileNotFoundError(f"源文件不存在: {source}")
            
        # 规范化目标路径
        destination = os.path.abspath(destination)
        os.makedirs(os.path.dirname(destination), exist_ok=True)
            
        shutil.move(source, destination)
        print(f"文件已移动到: {destination}")
        return True
    except Exception as e:
        print(f"移动文件失败: {str(e)}")
        return False

@dataclass
class ProcessResult:
    """视频处理结果数据类"""
    success: bool
    video_url: Optional[str]
    file_path: Optional[str]
    transcription: Optional[str]
    elapsed_times: Dict[str, float]  # 各阶段耗时
    error: Optional[str]
    
    def to_json(self) -> str:
        """转换为JSON字符串"""
        return json.dumps(self.__dict__, ensure_ascii=False, indent=2)

def process_douyin_video(url_input: str, target_path: Optional[str] = None) -> ProcessResult:
    """
    处理抖音视频并返回结构化结果
    
    参数:
        url_input: 抖音分享内容或URL
        target_path: 可选的目标保存路径
        
    返回:
        ProcessResult: 包含处理结果的数据对象
    """
    result = ProcessResult(
        success=False,
        video_url=None,
        file_path=None,
        transcription=None,
        elapsed_times={},
        error=None
    )
    
    try:
        start_time = time.time()
        
        if not url_input:
            url_input = input("请输入抖音分享内容: ").strip()
        
        # 提取URL
        url = extract_url(url_input)
        result.elapsed_times['extract_url'] = time.time() - start_time
        
        douyin_shortlink_id = extract_douyin_shortlink_id(url)
        # 检查目录目录下是否有已翻译好的文案，如果有，则直接返回文案
        download_dir = os.getenv('DOWNLOAD_DIR')
        if not download_dir:
                print("未设置下载目录，继续往下处理")
        else:
            print(f"下载目录: {download_dir}")
            
            transcription_file = os.path.join(download_dir, douyin_shortlink_id + ".txt")
            if os.path.exists(transcription_file):
                print("找到已翻译好的文案，直接返回")
                with open(transcription_file, 'r', encoding='utf-8') as f:
                    result.transcription = f.read()
                result.success = True
                result.elapsed_times['get_page'] = 0
                result.elapsed_times['total'] = time.time() - start_time
                return result
        
        # 获取页面内容 现在这一步耗时很长，需要优化
        html_content = get_real_page(url)
        result.elapsed_times['get_page'] = time.time() - start_time
        
        # 解析视频URL
        video_url = extract_video_url(html_content)
        if not video_url:
            raise ValueError("未找到视频URL")
        result.video_url = video_url
        result.elapsed_times['parse_video_url'] = time.time() - start_time
        
        # 下载视频
        downloader = DouyinDownloader()
        file_name = douyin_shortlink_id + ".mp4"
        if not downloader.download(video_url, file_name):
            raise RuntimeError("视频下载失败")
        result.elapsed_times['download'] = time.time() - start_time
        
        # 处理文件路径
        if target_path:
            move_file(downloader.last_downloaded_filename, target_path)
            result.file_path = target_path
        else:
            # 阿里云无法直接访问抖音视频地址，需要转存到本机的nginx目录下，才可以正常访问
            if not download_dir:
                print("未设置下载目录，无法进行文案提取")
            else:
                dest_path = os.path.join(download_dir, file_name)
                move_file(downloader.last_downloaded_filename, dest_path)
                result.file_path = dest_path
                
                # 语音转文字
                processor = SpeechToTextProcessor()
                print("正在进行语音转文字...")
                # 调用阿里百炼模型，让它到我自己的服务器上下载视频，然后进行语音转文字
                result.transcription = processor.transcribe(f"https://www.myaiweb.cn/tmp/{file_name}")
                print("语音转文字完成，开始异步压缩视频，并保存结果")
                # 调用gzip对视频文件进行异步压缩
                compress_video_async(dest_path)
                
                # 将文案保存到download_dir目录下，文件名与视频文件名相同，后缀为.txt
                # 这是为了缓存文案提取结果，下次请求获取相同视频文案可以减少资源消耗
                transcription_file = os.path.join(download_dir, douyin_shortlink_id + ".txt")
                with open(transcription_file, 'w', encoding='utf-8') as f:
                    f.write(result.transcription)
            
        result.success = True
        result.elapsed_times['total'] = time.time() - start_time
        
    except Exception as e:
        result.error = str(e)
        result.success = False
    
    return result

if __name__ == "__main__":
    url_input = sys.argv[1] if len(sys.argv) > 1 else None
    target_path = sys.argv[2] if len(sys.argv) > 2 else None
    
    result = process_douyin_video(url_input, target_path)
    print("result:")
    print(result.to_json())
    

